package com.dc.base.vm

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dc.base.livedata.EventLiveData
import com.dc.base.network.BaseResponse
import com.dc.base.network.ExceptionHandle
import kotlinx.coroutines.*

open class BaseViewModel : ViewModel() {

    /**
     * 错误信息LiveData
     */
    val errorLiveData = MutableLiveData<AppException>()

    /**
     * 无更多数据LiveData
     */
    val noMoreLiveData = MutableLiveData<Boolean>()

    /**
     * 无数据LiveData
     */
    val emptyLiveData = MutableLiveData<Any>()

    private val loadingChange: UiLoadingChange by lazy { UiLoadingChange() }

    /**
     * Retrofit2.6.0前，使用协程，api请求后返回的数据需要使用Call或者Defeerd包裹，2.6.0开始，方法加上suspend可以直接返回数据。
     * 协程 + Retrofit（2.6.0开始）使用同步代码处理异步的网络请求，suspend方法在retrofit内部会切到子线程
     *
     * @param block 请求体方法，必须要用suspend关键字修饰
     * @param success 成功回调
     * @param error 失败回调 可不传
     * @param isShowLoading 是否显示加载框
     * @param loadingMessage 加载框提示内容
     */
    protected fun <T> request(
        block: suspend () -> BaseResponse<T>,
        success: (T) -> Unit,
        error: (AppException) -> Unit = {},
        isShowLoading: Boolean = false,
        loadingMessage: String = "请求网络中..."
    ) {
        viewModelScope.launch {
            runCatching {
                if (isShowLoading) {
                    loadingChange.showLoadingDialog.postValue(loadingMessage)
                }
                block()
            }.onSuccess {
                // 网络请求成功
                loadingChange.dismissLoadingDialog.postValue(true)
                runCatching {
                    executeResponse(it) { t ->
                        success(t)
                    }
                }.onFailure {
                    //失败回调
                    error(ExceptionHandle.handleException(it))
                }
            }.onFailure {
                loadingChange.dismissLoadingDialog.postValue(true)
                error(ExceptionHandle.handleException(it))
            }
        }
    }

    /**
     * 调用协程
     * @param block 操作耗时操作任务
     * @param success 成功回调
     * @param error 失败回调
     */
    protected fun <T> launch(
        block: suspend () -> T,
        success: (T) -> Unit = {},
        error: (Throwable) -> Unit = {},
    ) {
        viewModelScope.launch {
            runCatching {
                withContext(Dispatchers.IO) {
                    block()
                }
            }.onSuccess {
                success(it)
            }.onFailure {
                error(it)
            }
        }
    }

    /**
     * 请求结果过滤，判断请求服务器请求结果是否成功，不成功则会抛出异常
     */
    private suspend fun <T> executeResponse(
        response: BaseResponse<T>,
        success: suspend CoroutineScope.(T) -> Unit
    ) {
        coroutineScope {
            when {
                response.isSuccess() -> {
                    success(response.getResponseData())
                }
                else -> {
                    throw AppException(
                        response.getResponseCode(),
                        response.getResponseMsg(),
                        response.getResponseMsg()
                    )
                }
            }
        }
    }


    inner class UiLoadingChange {

        // 显示加载框
        val showLoadingDialog by lazy { EventLiveData<String>() }

        //隐藏
        val dismissLoadingDialog by lazy { EventLiveData<Boolean>() }
    }
}